const Log = require('../libs/log4js');

class DBUtils {

  constructor({DB, logName}) {
    this.DB = DB;
    this.log = Log(logName || DB.modelName);
  }

  insert({data}) {
    data.createDate = data.updateDate = Date.now() + '';
    return new Promise((s, r) => {
      const db = new this.DB(data);
      db.save((err) => {
        if (err) {
          this.log.warn('数据保存失败');
          console.log(err);
          r(0);
        }
        this.log.info('数据存储成功');
        s(1);
      });
    });
  }

  queryAll({queryData = {}, options = {}, sort = {}} = {}) {
    options = Object.assign(options, {_id: 0, __v: 0});
    return new Promise((s, r) => {
      if (Object.keys(sort).length) {
        this.DB.find(queryData, options)
          .sort(sort)
          .exec((err, data) => {
            if (err) {
              this.log.warn('<<< 查询失败');
              console.error(err);
              this.log.warn('查询失败 >>>');
              r(0);
              return;
            }
            this.log.info('<<< 查询成功');
            // console.log(data);
            // this.log.info('查询成功 >>>');
            s(data);
          });
      } else {
        this.DB.find(queryData, options)
          .exec((err, data) => {
            if (err) {
              this.log.warn('<<< 查询失败');
              console.error(err);
              this.log.warn('查询失败 >>>');
              r(0);
              return;
            }
            this.log.info('<<< 查询成功');
            // console.log(data);
            // this.log.info('查询成功 >>>');
            s(data);
          });
      }
    });
  }

  /**
   *
   * options可选值
   * safe （布尔值）安全模式（默认为在架构（true）中设置的值）
   * upsert （布尔值）是否创建不匹配的文档（假）
   * multi （布尔值）是否应更新多个文档（假）
   * runValidators：如果为true，则对此命令运行更新验证程序。更新验证器根据模型的架构验证更新操作。
   * setDefaultsOnInsert：如果upsert为true，则在创建新文档时，
   *  将应用模型模式中指定的默认值。此选项仅在MongoDB> = 2.4上有效，
   *  因为它依赖于MongoDB的$setOnInsertoperator。
   * strict（布尔值）会覆盖strict此更新的选项
   * overwrite （布尔值）禁用仅更新模式，从而允许您覆盖文档（false）
   * */
  update({queryData, data, options = {}}) {
    return new Promise((s, r) => {
      data.updateDate = Date.now();
      this.DB.update(queryData, data, options)
        .exec((err, data) => {
          if (err) {
            this.log.warn('<<< 更新失败');
            console.error(err);
            this.log.warn('更新失败 >>>');
            r(0);
            return;
          }
          // console.log(data);
          this.log.info('更新成功');
          s(1);
        });
    });
  }

  deleteMany({queryData}) {
    return new Promise((s, f) => {
      this.DB.deleteMany(queryData)
        .exec((err, data) => {
          if (err) {
            this.log.warn('<<< 删除失败');
            console.error(err);
            this.log.warn('删除失败 >>>');
            r(0);
            return;
          }
          // console.log(data);
          this.log.info(JSON.stringify(queryData), `删除成功, 删除${data.n}条数据`);
          s(1);
        });
    });
  }

  deleteOne({queryData}) {
    return new Promise((s, f) => {
      this.DB.deleteMany(queryData)
        .exec((err) => {
          if (err) {
            this.log.warn('<<< 删除失败');
            console.error(err);
            this.log.warn('删除失败 >>>');
            r(0);
            return;
          }
          this.log.info('删除成功');
          s(1);
        });
    });
  }

  computedCount(queryData = {}) {
    return new Promise((s, r) => {
      this.DB.find(queryData).countDocuments()
        .exec((err, data) => {
          if (err) {
            this.log.warn('<<< 查询失败');
            console.error(err);
            this.log.warn('查询失败 >>>');
            r(0);
            return;
          }
          this.log.info('<<< 查询成功');
          s(data);
        });
    });
  }

  queryByPageNo({queryData = {}, options = {}, sort = {}, skip = 0, limit = 10} = {}) {
    options = Object.assign(options, {_id: 0, __v: 0});
    return new Promise((s, r) => {
      this.DB.find(queryData, options)
        .sort(sort)
        .skip(skip)
        .limit(limit)
        .exec((err, data) => {
          if (err) {
            this.log.warn('<<< 分页查询失败');
            console.error(err);
            this.log.warn('分页查询失败 >>>');
            r(0);
            return;
          }
          this.log.info('<<< 分页查询成功');
          s(data);
        });
    });
  }
}

module.exports = DBUtils;
